//
//  main.m
//  block
//
//  Created by admin on 2019/8/5.
//  Copyright © 2019 猫爷爷的酱醋茶. All rights reserved.
//
/*
 
 block
    是将函数及其执行上下文封装起来的对象。
 
    本质是一个数据类型
    数据类型的作用，可以根据数据类型的模板，在内存中申请空间。
 

 block
    如果忘记语法格式，可以通过inlineBlock只能提示
 
 1. 声明的语法格式：
 
     返回值类型 (^block变量的名称)(参数列表);
         例：void (^myBlockOne)();  代表声明了一个block类型的变量，名称叫做myBlockOne 这个变量中只能存储没有返回值没有参数的代码段。
         例：int (^myBlockTwo)();   代表声明了一个block类型的变量，名称叫做myBlockTwo 这个变量中只能存储int返回值没有参数的代码段。
         int (^myBlockThree)(int num1,int num2); 代表声明了一个block类型的变量, 这个变量中只能存储int返回值两个整型参数的代码段。
 
 2. 初始化的语法格式：
     ^返回值类型(参数列表){
        //代码段
     };
 
     例：myBlockOne = ^void(){
        NSLog(@"猫爷爷的酱醋茶，要继续努力啊！");
        };
 
 3. 执行block中的代码段
    block变量的名称();
 
    例：myBlockOne();
 
 4. 语法简写
    1）无论block声明中是否有返回值，初始化都可以省略，如果block声明中无参数，那么初始化的时候，也可以省略参数
     void (^myBlockOne)() = ^{
        NSLog(@"猫爷爷的酱醋茶，要继续努力啊！");
     }
 
     2）block声明可以省略参数名
     int (^myBlockThree)(int,int);
 
 5. 用typedef简化block变量的复杂定义
    使用：typedef 返回值类型 (^新类型)(参数列表);
 
     typedef void(^NewTypeOne)(); 代表重新定义了一个类型叫做NewTypeOne的一个block类型，无参数无返回值的block类型。
 
     例：typedef void(^SayHi)(void);
        SayHi Hello = ^{
            NSLog(@"大家好，我是猫爷爷的酱醋茶");
        };
 
        Hello();
 
     typedef int(^Sum)(int num1,int num2); 代表重新定义了一个类型叫做Sum，是有参数有返回值的block类型。
 
     例：typedef int(^Sum)(int num1,int num2);
 
         Sum sum = ^int(int num1,int  num2){
         return  num1 + num2;
         };
 
         int num = sum(1,2);
         NSLog(@"num = %d",num);
 
 6. block代码块访问外部变量 - 例：LocalVariableModifier();
    1）在block代码块的内部可以取定义在外部变量的值，包括全局变量和局部变量
    2）在block代码块的内部可以修改全局变量的值，但是不能修改定义在外部的局部变量的值
    3）如果需要定义在外部的局部变量允许block代码块内部进行修改，那么就在这个局部变量的前面加一个__block的修饰符。
 
 7. 将block作为函数的参数  例：FunctionWithBlock(); TraversingArray();
     可以实现将调用者自己写的代码，传递到函数内部执行。/函数内部预留代码给外部使用者实现自己的逻辑。
 
 8. 将block作为函数的返回值 例：ReturnBlock();
    返回值类型必须用typedef定义为短类型。
 
 9. block和函数 ：都是封装一段代码
 
 10. block作为属性的时候为什么要用copy修饰
    使用copy是对block作了一个转换，
    将存储在栈区的block（__NSStackBlock__）（会被系统自动回收）拷贝一份到堆区，变成（__NSMallocBlock）
 
 
 
 */

#import <Foundation/Foundation.h>
#import "ArraySort.h"
#import "CustomArray.h"

//亚洲国家名
char *countries[] =
{
    "Nepal",
    "Cambodia",
    "Afghanistan",
    "China",
    "Singapore",
    "Bangladesh",
    "India",
    "Maldives",
    "South Korea",
    "Bhutan",
    "Japan",
    "Sikkim",
    "Sri Lanka",
    "Burma",
    "North Korea",
    "Laos",
    "Malaysia",
    "Indonesia",
    "Turkey",
    "Mongolia",
    "Pakistan",
    "Philippines",
    "Vietnam",
    "Palestine"
};

//typedef的应用
void testTheTypedef(void);

typedef void(^NewType)(void);

//__block局部变量修饰符
void LocalVariableModifier(void);

//全局变量
int num1 = 100;

//block作为函数参数的例子
void FunctionWithBlock(void);

//block作为参数遍历数组
void TraversingArray(void);

//block作为函数的返回值
NewType ReturnBlock(void);

//block异步加载
void asyncLoading(void (^finished)(NSString *html));

//


int main(int argc, const char * argv[])
{

//    TraversingArray();
//
//    NewType testBlock = ReturnBlock();
//    testBlock();
    
//    asyncLoading(^(NSString *html) {
//        NSLog(@"完成异步回调 %@",html);
//    });
    
    
    //第一种block 全局block __NSGlobalBlock__ 本质是函数，存储在代码区 基本不这么使用
    void (^demo)(void) = ^(){
        NSLog(@"aaa");
    };
    
    NSLog(@"%@",demo);
    
    //第二种block 在ARC模式下，系统自动包装block为 堆区Block__NSMallocBlock__ ；开启MRC 本质是__NSStackBlock__的
    int num = 5;
    void (^demo2)(void) = ^(){
        NSLog(@"aaa %d",num);
    };
    NSLog(@"%@",demo2);
    
    
    
    return 0;
}


//block异步加载 - GCD
void asyncLoading(void (^finished)(NSString *html))
{
    //放入主队列
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"耗时操作");
        
        //通常加载数据...
        
        //异步完成之后，准备主线程回调
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"准备主线程回调");
            
            finished(@"<html>");
        });
    });
    
    
}


//block作为函数的返回值
NewType ReturnBlock(void)
{
    
    void (^blockOne)(void) = ^{
        NSLog(@"~~~~~~~");
        NSLog(@"~~~~~~~");
        NSLog(@"~~~~~~~");
    };
    
    return blockOne;
    
    
}

//block作为参数遍历数组
void TraversingArray(void)
{
    
    CustomArray *array = [CustomArray new];
    
    [array TraversingWithBlock:^(int array) {
        NSLog(@"%d",array);
    }];
    
    
}

//block作为函数参数的例子
void FunctionWithBlock(void)
{

    
    ArraySort *array = [ArraySort new];
    
    int length = sizeof(countries)/sizeof(countries[0]);

    //按字母顺序排序国家名
    [array sortWithArray:countries andLength:length andCompareBlock:^BOOL(char * _Nonnull ObjectOne, char * _Nonnull ObjectTwo) {
        
        int res = strcmp(ObjectOne, ObjectTwo);
        
        return res > 0;
    }];
    
    for (int i = 0; i < length; i++)
    {
        NSLog(@"%s",countries[i]);
    }
    
    NSLog(@"------------------------------");
    
    //按国家长度排序
    [array sortWithArray:countries andLength:length andCompareBlock:^BOOL(char * _Nonnull ObjectOne, char * _Nonnull ObjectTwo) {
        
        int res = (int)strlen(ObjectOne) - (int)strlen(ObjectTwo);
        
        if (res > 0)
        {
            return YES;
        }
        return NO;
        
    }];
    
    for (int i = 0; i < length; i++)
    {
        NSLog(@"%s",countries[i]);
    }
    
}

//局部变量修饰符
void LocalVariableModifier(void)
{
    //如果允许被block内部修改，需要加__block
    __block int num2 = 200; //局部变量
    
    NewType blockOne = ^{
        
        int num3 = 300;
        num1 += 1;
        num2 += 1;//局部变量在内部修改值，需要添加__block
        num3 += 1;
        
        NSLog(@"num1 = %d,num2 = %d,num3 = %d",num1,num2,num3);
        
    };
    
    blockOne();
}


//typedef的应用
void testTheTypedef(void)
{
    typedef int(^Sum)(int num1,int num2);
    
    Sum sum = ^int(int num1,int  num2){
        return  num1 + num2;
    };
    
    int num = sum(1,2);
    NSLog(@"num = %d",num);
}
